using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Forms;
using AntEater.ComponentModel;
using AntEater.ComponentModel.BuildElements;

namespace AntEater.Runtime.UI
{
    /// <summary>
    /// Visualizes a Build File as a tree node.
    /// </summary>
    internal class TargetExecutionBuildFileTreeNode : TreeNode
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TargetExecutionBuildFileTreeNode"/> class.
        /// </summary>
        public TargetExecutionBuildFileTreeNode()
            : base() {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TargetExecutionBuildFileTreeNode"/> class.
        /// </summary>
        /// <param name="buildFile">The build file.</param>
        /// <param name="options">The options.</param>
        public TargetExecutionBuildFileTreeNode(BuildFile buildFile, Options options)
            : this() {

            this._buildFile = buildFile;
            this._buildFile.Changed += new EventHandler<EventArgs>(this.Changed);

            this._options = options;

            // Set node properties
            this.Name = this._buildFile.BuildFilePath;
            this.Text = this._buildFile.Name;
            this.ToolTipText = this._buildFile.BuildFilePath;
            this.ImageKey = "BuildFile";
            this.SelectedImageKey = "BuildFile";

            this.RefreshNodes();
        }

        private BuildFile _buildFile;

        /// <summary>
        /// Gets the build file.
        /// </summary>
        /// <value>The build file.</value>
        public BuildFile BuildFile {
            get { return _buildFile; }
        }

        private Options _options;

        /// <summary>
        /// Gets the options.
        /// </summary>
        /// <value>The options.</value>
        public Options Options {
            get { return _options; }
        }

        /// <summary>
        /// Refreshes the nodes.
        /// </summary>
        private void RefreshNodes() {

            this.Nodes.Clear();

            // Add Targets
            if (this.BuildFile.Definition != null) {

                SortedList<string, TargetBuildElement> targets = new SortedList<string, TargetBuildElement>(StringComparer.InvariantCultureIgnoreCase);
                SortedList<string, SortedList<string, TargetBuildElement>> importedBuildFiles = new SortedList<string, SortedList<string, TargetBuildElement>>(StringComparer.InvariantCultureIgnoreCase);
                TargetCollection defaultTargets = this.BuildFile.Definition.GetDefaultTargets();

                // split targets in to collections for imported targest and not imported targets
                foreach (TargetBuildElement target in this.BuildFile.Definition.Targets) {
                    if (!target.IsImported) {
                        if (!targets.ContainsKey(target.Name)) {
                            targets.Add(target.Name, target);
                        }
                    } else {
                        // split the imported targets in a collection for each build file
                        if (!importedBuildFiles.ContainsKey(target.Root.BuildFilePath)) {
                            importedBuildFiles.Add(target.Root.BuildFilePath, new SortedList<string, TargetBuildElement>(StringComparer.InvariantCultureIgnoreCase));
                        }
                        if (!importedBuildFiles[target.Root.BuildFilePath].ContainsKey(target.Name)) {
                            importedBuildFiles[target.Root.BuildFilePath].Add(target.Name, target);
                        }
                    }
                }

                // Add all local targets
                foreach (TargetBuildElement target in targets.Values) {
                    this.Nodes.Add(new TargetExecutionTargetTreeNode(target, this.BuildFile, defaultTargets.Contains(target.Name)));
                }

                if (this.Options.ShowImportedTargets == true) {

                    // Add all imported targets
                    foreach (string key in importedBuildFiles.Keys) {

                        TreeNode importedNode = this.Nodes.Add(key, Path.GetFileName(key), "Folder", "Folder");
                        importedNode.ToolTipText = key;
                        SortedList<string, TargetBuildElement> importedTargets = importedBuildFiles[key];

                        foreach (TargetBuildElement importedTarget in importedTargets.Values) {
                            importedNode.Nodes.Add(new TargetExecutionTargetTreeNode(importedTarget, this.BuildFile, defaultTargets.Contains(importedTarget.Name)));
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Changeds the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Changed(object sender, EventArgs e) {
            RefreshNodes();
        }
    }
}
